package org.wangp.framework.core.config

import cn.hutool.core.date.DatePattern
import cn.hutool.core.date.DateTime
import cn.hutool.core.date.DateUtil
import cn.hutool.core.util.StrUtil
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.core.json.JsonReadFeature
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer
import org.springframework.boot.autoconfigure.AutoConfigureAfter
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
import org.springframework.stereotype.Component
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import java.util.*
import javax.annotation.PostConstruct
import javax.annotation.Resource

/**
 * @author wangpeng (๑•ᴗ•๑)
 * @date 2021/10/20 15:08
 */
@Component
@AutoConfigureAfter(value = [JacksonAutoConfiguration::class])
class JsonConfiguration {

	@Resource
	private lateinit var objectMapper: ObjectMapper

	@PostConstruct
	fun init() {
		objectMapper.apply {
			configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
			configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
			configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true)
			configure(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS.mappedFeature(), true)
			disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
			setSerializationInclusion(JsonInclude.Include.NON_NULL)
			propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE
			enable(MapperFeature.USE_STD_BEAN_NAMING)
			dateFormat = SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN)
			setTimeZone(TimeZone.getTimeZone("GMT+8"))
			objectMapper.registerModule(JavaTimeModule().apply {
				addSerializer(
					LocalDateTime::class.java,
					LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN))
				)
				addSerializer(
					LocalDate::class.java,
					LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN))
				)
				addSerializer(
					LocalTime::class.java,
					LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN))
				)
				addDeserializer(
					LocalDateTime::class.java,
					LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN))
				)
				addDeserializer(
					LocalDate::class.java,
					LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN))
				)
				addDeserializer(
					LocalTime::class.java,
					LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN))
				)
			})
		}
	}
}

infix fun ObjectMapper.toJsonString(data: Any): String = this.writeValueAsString(data) ?: StrUtil.EMPTY_JSON

inline infix fun <reified T> ObjectMapper.toObj(json: String): T? {
	if (json.isBlank()) return null
	return this.readValue(json, T::class.java)
}

inline infix fun <reified T> ObjectMapper.toObjType(json: String): T? {
	if (json.isBlank()) return null
	return this.readValue(json, object : TypeReference<T>() {})
}



